package com.ikingtech.platform.service.system.dept.service.repository;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.department.api.DeptOrgApi;
import com.ikingtech.framework.sdk.department.api.DeptUserApi;
import com.ikingtech.framework.sdk.department.model.DeptBasicDTO;
import com.ikingtech.framework.sdk.department.model.DeptDTO;
import com.ikingtech.framework.sdk.department.model.DeptManagerDTO;
import com.ikingtech.framework.sdk.department.model.DeptOrgDTO;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.platform.service.system.dept.entity.DepartmentDO;
import lombok.RequiredArgsConstructor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author tie yan
 */
@RequiredArgsConstructor
public class ModelConverter {

    private final DeptRepository repo;

    private final DeptUserApi deptUserApi;

    private final DeptOrgApi deptOrgApi;

    public List<DeptBasicDTO> modelInfoConvert(List<DepartmentDO> entities) {
        List<DeptOrgDTO> organizations = this.deptOrgApi.loadByIds(Tools.Coll.convertList(entities, DepartmentDO::getOrgId));
        Map<String, DeptOrgDTO> orgMap = Tools.Coll.convertMap(organizations, DeptOrgDTO::getId);
        return Tools.Coll.convertList(entities, entity -> this.modelInfoConvert(entity, orgMap.get(entity.getOrgId())));
    }

    public List<DeptDTO> modelConvert(List<DepartmentDO> entities) {
        if (Tools.Coll.isBlank(entities)) {
            return new ArrayList<>();
        }
        List<DepartmentDO> subEntities = this.repo.list(
                Wrappers.<DepartmentDO>lambdaQuery()
                        .or(
                                wrapper ->
                                        Tools.Coll.convertList(entities, DepartmentDO::getFullPath).forEach(fullPath ->
                                                wrapper.likeRight(DepartmentDO::getFullPath, fullPath))
                        )
                        .orderByDesc(DepartmentDO::getCreateTime)
        );
        Map<String, Integer> userCountMap = this.deptUserApi.getUserCount(Tools.Coll.convertList(subEntities, DepartmentDO::getId));
        List<DeptManagerDTO> managers = this.deptUserApi.loadManagers(Tools.Coll.convertList(entities, DepartmentDO::getManagerId));
        Map<String, DeptManagerDTO> managerMap = Tools.Coll.convertMap(managers, DeptManagerDTO::getUserId, manager -> manager);
        List<DeptOrgDTO> organizations = this.deptOrgApi.loadByIds(Tools.Coll.convertList(entities, DepartmentDO::getOrgId));
        Map<String, DeptOrgDTO> orgMap = Tools.Coll.convertMap(organizations, DeptOrgDTO::getId);
        return Tools.Coll.convertList(entities, entity -> {
            List<String> subEntityIds = Tools.Coll.flatMap(
                    Tools.Coll.filter(subEntities, subEntity -> subEntity.getFullPath().startsWith(entity.getFullPath())),
                    subEntity -> Tools.Str.split(subEntity.getFullPath().substring(subEntity.getFullPath().indexOf(subEntity.getId())), "@"),
                    Collection::stream
            );
            return this.modelConvert(entity, managerMap.get(entity.getManagerId()), Tools.Coll.mapFilter(userCountMap, entry -> subEntityIds.contains(entry.getKey())), orgMap.get(entity.getOrgId()));
        });
    }

    public DeptDTO modelInfoConvert(DepartmentDO entity, DeptOrgDTO organization) {
        DeptDTO dept = Tools.Bean.copy(entity, DeptDTO.class);
        if (null != organization) {
            dept.setOrgName(organization.getName());
        }
        return dept;
    }

    public DeptDTO modelConvert(DepartmentDO entity,
                                DeptManagerDTO manager,
                                Map<String, Integer> userCountMap,
                                DeptOrgDTO organization) {
        DeptDTO dept = Tools.Bean.copy(entity, DeptDTO.class);
        dept.setManager(manager);
        dept.setUserCount(Tools.Coll.mapSum(userCountMap));
        dept.setInDataScope(Tools.Coll.isBlank(Me.dataScope()) || Me.dataScope().contains(dept.getId()));
        if (null != organization) {
            dept.setOrgName(organization.getName());
        }
        return dept;
    }
}
